/**
 *                            License
 * THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS  
 * CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). 
 * THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW.  
 * ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR  
 * COPYRIGHT LAW IS PROHIBITED.
 * 
 * BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND  
 * AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE  
 * MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED 
 * HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
 * 
 */
package l1j.server.server.clientpackets;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.List;

import l1j.server.Config;
import l1j.server.L1DatabaseFactory;
import l1j.server.server.ClientThread;
import l1j.server.server.datatables.NpcTable;
import l1j.server.server.datatables.PetTable;
import l1j.server.server.datatables.ShopTable;
import l1j.server.server.model.L1Inventory;
import l1j.server.server.model.L1Object;
import l1j.server.server.model.L1World;
import l1j.server.server.model.Instance.L1ItemInstance;
import l1j.server.server.model.Instance.L1NpcInstance;
import l1j.server.server.model.Instance.L1PcInstance;
import l1j.server.server.model.Instance.L1PetInstance;
import l1j.server.server.model.identity.L1ItemId;
import l1j.server.server.model.shop.L1Shop;
import l1j.server.server.model.shop.L1ShopBuyOrderList;
import l1j.server.server.model.shop.L1ShopSellOrderList;
import l1j.server.server.model.trade.L1Trade;
import l1j.server.server.serverpackets.S_ServerMessage;
import l1j.server.server.templates.L1Npc;
import l1j.server.server.templates.L1Pet;
import l1j.server.server.templates.L1PrivateShopBuyList;
import l1j.server.server.templates.L1PrivateShopSellList;
import l1j.server.server.utils.SQLUtil;

/**
 * TODO 翻譯，好多 處理收到由客戶端傳來取得結果的封包
 */
public class C_Result extends ClientBasePacket {

	private static final String C_RESULT = "[C] C_Result";

	private L1PcInstance pc;

	private L1Object findObject;

	private int size;

	private int npcId = 0;

	public C_Result(byte abyte0[], ClientThread clientthread) throws Exception {
		super(abyte0);
		int npcObjectId = readD();
		findObject = L1World.getInstance().findObject(npcObjectId);
		pc = clientthread.getActiveChar();
		if (pc == null || findObject == null) {
			return;
		}
		int diffLocX = Math.abs(pc.getX() - findObject.getX());
		int diffLocY = Math.abs(pc.getY() - findObject.getY());
		// 3格以上的距離視為無效要求
		if ((diffLocX > 3) || (diffLocY > 3)) {
			return;
		}

		int resultType = readC();
		size = readH();
		if (size <= 0)
			return;
		int level = pc.getLevel();

		String npcImpl = "";
		boolean isPrivateShop = false;

		if (findObject instanceof L1NpcInstance) {
			L1NpcInstance targetNpc = (L1NpcInstance) findObject;
			npcId = targetNpc.getNpcTemplate().get_npcId();
			npcImpl = targetNpc.getNpcTemplate().getImpl();
		} else if (findObject instanceof L1PcInstance) {
			isPrivateShop = true;
		} else {
			return;
		}

		if (npcImpl.equalsIgnoreCase("L1Merchant")) {
			L1Shop shop = ShopTable.getInstance().get(npcId);
			if (resultType == 0) { // 購買道具
				buyItem(shop);
			} else if (resultType == 1) {// 賣道具
				sellItem(shop);
			} else if (resultType == 12) { // 領寵物
				getPets();
			}
		} else if (npcImpl.equalsIgnoreCase("L1Dwarf") && (level >= 5)) {
			if (resultType == 2) {
				dwarfIn();
			} else if (resultType == 3) {
				dwarfOut();
			}
		} else if (isPrivateShop) { // 個人商店
			if (resultType == 0) {// 買
				privateShopBuy();
			} else if (resultType == 1) {// 賣
				privateShopSell();
			}
		}
		pc.saveInventory();
	}

	private void buyItem(L1Shop shop) {
		L1ShopBuyOrderList orderList = shop.newBuyOrderList();
		for (int i = 0; i < size; i++) {
			int order = readD();
			int count = readD();
			if (order < 0 || count <= 0)
				return;
			orderList.add(order, count);
		}
		shop.sellItems(pc, orderList);
	}

	private void sellItem(L1Shop shop) {
		L1ShopSellOrderList orderList = shop.newSellOrderList(pc);
		for (int i = 0; i < size; i++) {
			int order = readD();
			int count = readD();
			if (order < 0 || count <= 0)
				return;
			orderList.add(order, count);
		}
		shop.buyItems(orderList);
	}

	private void getPets() {
		int petCost, petCount, divisor, itemObjectId, itemCount = 0;
		boolean chackAdena = true;

		for (int i = 0; i < size; i++) {
			petCost = 0;
			petCount = 0;
			divisor = 6;
			itemObjectId = readD();
			itemCount = readD();

			if (itemCount <= 0 || itemObjectId <= 0) {
				return;
			}
			for (L1NpcInstance petNpc : pc.getPetList().values())
				petCost += petNpc.getPetcost();

			int charisma = pc.getCharisma();

			if (!pc.getInventory().consumeItem(L1ItemId.ADENA, 115)) {
				chackAdena = false;
			}
			L1Pet l1pet = PetTable.getInstance().getTemplate(itemObjectId);
			if (l1pet != null && chackAdena) {
				npcId = l1pet.get_npcid();
				charisma -= petCost;
				if ((npcId == 45313) || (npcId == 45710 // タイガー、バトルタイガー
						) || (npcId == 45711) || (npcId == 45712)) { // 紀州犬の子犬、紀州犬
					divisor = 12;
				} else {
					divisor = 6;
				}
				petCount = charisma / divisor;
				if (petCount <= 0) {
					pc.sendPackets(new S_ServerMessage(489)); // 你無法一次控制那麼多寵物。
					return;
				}
				L1Npc npcTemp = NpcTable.getInstance().getTemplate(npcId);
				L1PetInstance pet = new L1PetInstance(npcTemp, pc, l1pet);
				pet.setPetcost(divisor);
			}
		}
		if (!chackAdena) {
			pc.sendPackets(new S_ServerMessage(189)); // \f1金幣不足。
		}
	}

	private void dwarfIn() {
		int objectId, count;
		for (int i = 0; i < size; i++) {
			objectId = readD();
			count = readD();
			L1Object object = pc.getInventory().getItem(objectId);
			L1ItemInstance item = (L1ItemInstance) object;
			if (item == null || count <= 0) {
				return;
			}
			if (!L1Trade.isItemMovable(pc, item)) {
				continue;
			}
			if (pc.getDwarfInventory().checkAddItemToWarehouse(item, count,
					L1Inventory.WAREHOUSE_TYPE_PERSONAL) == L1Inventory.SIZE_OVER) {
				pc.sendPackets(new S_ServerMessage(75)); // \f1これ以上ものを置く場所がありません。
				break;
			}
			pc.getInventory()
					.tradeItem(objectId, count, pc.getDwarfInventory());
			pc.turnOnOffLight();
			logDwarf(item, count, "in  general");
		}
	}

	private void dwarfOut() {
		int objectId, count;
		L1ItemInstance item;
		for (int i = 0; i < size; i++) {
			objectId = readD();
			count = readD();
			item = pc.getDwarfInventory().getItem(objectId);
			if (item == null || count <= 0) {
				return;
			}
			if (item.getCount() < count) {
				return;
			}
			if (pc.getInventory().checkAddItem(item, count) == L1Inventory.OK) // 檢查重量與容量
			{
				if (pc.getInventory().consumeItem(L1ItemId.ADENA, 30)) {
					pc.getDwarfInventory().tradeItem(item, count,
							pc.getInventory());
					logDwarf(item, count, "out general");
				} else {
					pc.sendPackets(new S_ServerMessage(189)); // \f1アデナが不足しています。
					break;
				}
			} else {
				pc.sendPackets(new S_ServerMessage(270)); // \f1持っているものが重くて取引できません。
				break;
			}
		}
	}

	private void logDwarf(L1ItemInstance item, int count, String type) {
		if (!Config.writeWarehouseLog)
			return;
		Connection con = null;
		PreparedStatement pstm = null;
		try {
			con = L1DatabaseFactory.getInstance().getConnection();
			pstm = con
					.prepareStatement("INSERT INTO log_warehouse SET time=?,account=?,pcname=?,itemname=?,count=?,type=?,itemobj=?,pcobj=?");
			pstm.setTimestamp(1, new Timestamp(System.currentTimeMillis()));
			pstm.setString(2, pc.getAccountName());
			pstm.setString(3, pc.getName());
			pstm.setString(4, item.getName() + item.getLogName());
			pstm.setInt(5, count);
			pstm.setString(6, type);
			pstm.setInt(7, item.getId());
			pstm.setInt(8, pc.getId());
			pstm.execute();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			SQLUtil.close(pstm);
			SQLUtil.close(con);
		}
	}

	private void privateShopBuy() {
		L1PcInstance targetPc = (L1PcInstance) findObject;
		int order;
		int count;
		int price;
		List<L1PrivateShopSellList> sellList;
		L1PrivateShopSellList pssl;
		int itemObjectId;
		int sellPrice;
		int sellTotalCount;
		int sellCount;
		L1ItemInstance item;
		boolean[] isRemoveFromList = new boolean[8];

		if (targetPc.isTradingInPrivateShop()) {
			return;
		}
		sellList = targetPc.getSellList();
		synchronized (sellList) {
			// 売り切れが発生し、閲覧中のアイテム数とリスト数が異なる
			if (pc.getPartnersPrivateShopItemCount() != sellList.size()) {
				return;
			}
			targetPc.setTradingInPrivateShop(true);

			for (int i = 0; i < size; i++) { // 購入予定の商品
				order = readD();
				count = readD();
				pssl = sellList.get(order);
				itemObjectId = pssl.getItemObjectId();
				sellPrice = pssl.getSellPrice();
				sellTotalCount = pssl.getSellTotalCount(); // 売る予定の個数
				sellCount = pssl.getSellCount(); // 売った累計
				item = targetPc.getInventory().getItem(itemObjectId);
				if (item == null) {
					continue;
				}
				if (count > sellTotalCount - sellCount) {
					count = sellTotalCount - sellCount;
				}
				if (count == 0) {
					continue;
				}

				if (pc.getInventory().checkAddItem(item, count) == L1Inventory.OK) { // 容量重量確認及びメッセージ送信
					for (int j = 0; j < count; j++) { // オーバーフローをチェック
						if (sellPrice * j > 2000000000) {
							pc.sendPackets(new S_ServerMessage(904, // 総販売価格は%dアデナを超過できません。
									"2000000000"));
							targetPc.setTradingInPrivateShop(false);
							return;
						}
					}
					price = count * sellPrice;
					if (pc.getInventory().checkItem(L1ItemId.ADENA, price)) {
						L1ItemInstance adena = pc.getInventory().findItemId(
								L1ItemId.ADENA);
						if ((targetPc != null) && (adena != null)) {
							if (targetPc.getInventory().tradeItem(item, count,
									pc.getInventory()) == null) {
								targetPc.setTradingInPrivateShop(false);
								return;
							}
							pc.getInventory().tradeItem(adena, price,
									targetPc.getInventory());
							logPrivateShop(item.getId(),
									item.getName() + item.getLogName(), count,
									targetPc, pc, price);
							String message = item.getItem().getName() + " ("
									+ String.valueOf(count) + ")";
							targetPc.sendPackets(new S_ServerMessage(877, // %1%o
									// %0に販売しました。
									pc.getName(), message));
							pssl.setSellCount(count + sellCount);
							sellList.set(order, pssl);
							if (pssl.getSellCount() == pssl.getSellTotalCount()) { // 売る予定の個数を売った
								isRemoveFromList[order] = true;
							}
						}
					} else {
						pc.sendPackets(new S_ServerMessage(189)); // \f1アデナが不足しています。
						break;
					}
				} else {
					pc.sendPackets(new S_ServerMessage(270)); // \f1持っているものが重くて取引できません。
					break;
				}
			}
			// 売り切れたアイテムをリストの末尾から削除
			for (int i = 7; i >= 0; i--) {
				if (isRemoveFromList[i]) {
					sellList.remove(i);
				}
			}
			targetPc.setTradingInPrivateShop(false);
		}
	}

	private void privateShopSell() {
		int count;
		int order;
		List<L1PrivateShopBuyList> buyList;
		L1PrivateShopBuyList psbl;
		int itemObjectId;
		L1ItemInstance item;
		int buyPrice;
		int buyTotalCount;
		int buyCount;
		boolean[] isRemoveFromList = new boolean[8];

		L1PcInstance targetPc = null;
		if (findObject instanceof L1PcInstance) {
			targetPc = (L1PcInstance) findObject;
		}
		if (targetPc == null) {
			return;
		}
		if (targetPc.isTradingInPrivateShop()) {
			return;
		}
		targetPc.setTradingInPrivateShop(true);
		buyList = targetPc.getBuyList();

		for (int i = 0; i < size; i++) {
			itemObjectId = readD();
			count = readCH();
			order = readC();
			item = pc.getInventory().getItem(itemObjectId);
			if (item == null) {
				continue;
			}
			psbl = buyList.get(order);
			buyPrice = psbl.getBuyPrice();
			buyTotalCount = psbl.getBuyTotalCount(); // 買う予定の個数
			buyCount = psbl.getBuyCount(); // 買った累計
			if (count > buyTotalCount - buyCount) {
				count = buyTotalCount - buyCount;
			}
			if (item.isEquipped()) {
				// pc.sendPackets(new S_ServerMessage(905)); //
				// 無法販賣裝備中的道具。
				continue;
			}
			if (item.getBless() >= 128) { // 被封印的裝備
				// pc.sendPackets(new S_ServerMessage(210,
				// item.getItem().getName())); // \f1%0%d是不可轉移的…
				continue;
			}

			if (targetPc.getInventory().checkAddItem(item, count) == L1Inventory.OK) { // 容量重量確認及びメッセージ送信
				for (int j = 0; j < count; j++) { // オーバーフローをチェック
					if (buyPrice * j > 2000000000) {
						targetPc.sendPackets(new S_ServerMessage(904, // 総販売価格は%dアデナを超過できません。
								"2000000000"));
						return;
					}
				}
				if (targetPc.getInventory().checkItem(L1ItemId.ADENA,
						count * buyPrice)) {
					L1ItemInstance adena = targetPc.getInventory().findItemId(
							L1ItemId.ADENA);
					if (adena != null) {
						targetPc.getInventory().tradeItem(adena,
								count * buyPrice, pc.getInventory());
						pc.getInventory().tradeItem(item, count,
								targetPc.getInventory());
						logPrivateShop(item.getId(),
								item.getName() + item.getLogName(), count, pc,
								targetPc, count * buyPrice);
						psbl.setBuyCount(count + buyCount);
						buyList.set(order, psbl);
						if (psbl.getBuyCount() == psbl.getBuyTotalCount()) { // 買う予定の個数を買った
							isRemoveFromList[order] = true;
						}
					}
				} else {
					targetPc.sendPackets(new S_ServerMessage(189)); // \f1アデナが不足しています。
					break;
				}
			} else {
				pc.sendPackets(new S_ServerMessage(271)); // \f1相手が物を持ちすぎていて取引できません。
				break;
			}
		}
		// 買い切ったアイテムをリストの末尾から削除
		for (int i = 7; i >= 0; i--) {
			if (isRemoveFromList[i]) {
				buyList.remove(i);
			}
		}
		targetPc.setTradingInPrivateShop(false);
	}

	private void logPrivateShop(int itemObj, String item_name, int item_count,
			L1PcInstance from, L1PcInstance to, int price) {
		if (!Config.writepPrivateShopLog)
			return;
		Connection con = null;
		PreparedStatement pstm = null;
		try {
			con = L1DatabaseFactory.getInstance().getConnection();
			pstm = con
					.prepareStatement("INSERT INTO log_privateshop SET time=?,item_name=?,item_count=?,fromname=?,toname=?,itemobj=?,fromobj=?,toobj=?,price=?");
			pstm.setTimestamp(1, new Timestamp(System.currentTimeMillis()));
			pstm.setString(2, item_name);
			pstm.setInt(3, item_count);
			pstm.setString(4, from.getName());
			pstm.setString(5, to.getName());
			pstm.setInt(6, itemObj);
			pstm.setInt(7, from.getId());
			pstm.setInt(8, to.getId());
			pstm.setInt(9, price);
			pstm.execute();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			SQLUtil.close(pstm);
			SQLUtil.close(con);
		}
	}

	@Override
	public String getType() {
		return C_RESULT;
	}

}
